package com.jfinal.j2cache.util;

import javassist.*;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;
import net.sf.cglib.asm.$Type;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

public class ClassUtils {

    private static ClassPool pool = ClassPool.getDefault();

    static {
        pool.insertClassPath(new ClassClassPath(ClassUtils.class));
    }

    private static boolean sameType($Type[] types, Class<?>[] clazzes) {
        // 个数不同
        if (types.length != clazzes.length) {
            return false;
        }

        for (int i = 0; i < types.length; i++) {
            if (!$Type.getType(clazzes[i]).equals(types[i])) {
                return false;
            }
        }
        return true;
    }

    public static Map<String, Integer> getMethodParamNames(final Method m) {
        final Map<String, Integer> map = new HashMap<String, Integer>();

        String methodName = m.getName();
        String className = m.getDeclaringClass().getName();

        try {
            CtClass ctClass = pool.getCtClass(className);
            CtMethod cm = ctClass.getDeclaredMethod(methodName);
            MethodInfo methodInfo = cm.getMethodInfo();

            if (methodInfo.getAccessFlags() == AccessFlag.PUBLIC) {
                CodeAttribute codeAttribute = methodInfo.getCodeAttribute();
                if (codeAttribute != null) {
                    LocalVariableAttribute attr = (LocalVariableAttribute) codeAttribute
                            .getAttribute(LocalVariableAttribute.tag);
                    if (attr != null) {
                        int startIndex = getStartIndex(attr);
                        String[] paramNames = new String[cm.getParameterTypes().length];
                        int pos = Modifier.isStatic(cm.getModifiers()) ? 0 : 1;
                        for (int j = 0; j < paramNames.length; j++) {
                            paramNames[j] = attr.variableName(startIndex+j + pos);
                            map.put(paramNames[j], j);
                        }
                    }
                }
            }
        } catch (NotFoundException e) {
            e.printStackTrace();
        }
        return map;
    }

    private static int getStartIndex(LocalVariableAttribute attr) {

        int startIndex = 0;
        for (int i = 0; i < attr.length(); i++) {
            if ("this".equals(attr.variableName(i))) {
                startIndex = i;
                break;
            }
        }
        return startIndex;
    }
}